package com.enfi.api.modules.db.config;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @author wind
 * @since 2020-04-07 15:47:35
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    @Override
    protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
        if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) {
            request.setAttribute("javax.servlet.error.exception", ex, 0);
        }
        if(body==null){
            Map<String, Object> attributes = new LinkedHashMap();
            attributes.put("status",status.value());
            attributes.put("timestamp", new Date());
            attributes.put("error", status.getReasonPhrase());
            attributes.put("exception", ex.getClass().getSimpleName());
            if(ex instanceof BiException){
                BiException biException=(BiException)ex;
                if(biException.getErrors()!=null){
                    attributes.put("errors", biException.getErrors());
                }
            }
            attributes.put("message", ex.getMessage());
            String path = ((HttpServletRequest)((ServletWebRequest) request).getNativeRequest()).getRequestURI();
            if(path!=null){
                attributes.put("path", path);
            }
            body=attributes;
        }
        return new ResponseEntity(body, headers, status);
    }

    @ExceptionHandler(BiException.class)
    public ResponseEntity handleBiException(WebRequest request, BiException ex) {
        HttpHeaders headers = new HttpHeaders();
        return this.handleExceptionInternal(ex, (Object)null, headers, HttpStatus.BAD_REQUEST, request);
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity handleIllegalArgumentException(WebRequest request,IllegalArgumentException ex) {
        HttpHeaders headers = new HttpHeaders();
       return this.handleExceptionInternal(ex, (Object)null, headers, HttpStatus.BAD_REQUEST, request);
    }

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        List<FieldError> fieldErrors=ex.getBindingResult().getFieldErrors();
        List list=new LinkedList();
        String exception="";
        for (FieldError fieldError : fieldErrors) {
            if(StringUtils.isEmpty(exception)){
                exception=fieldError.getField()+"·"+fieldError.getDefaultMessage();
            }
            Map map=new LinkedHashMap();
            map.put("field",fieldError.getField());
            map.put("message",fieldError.getDefaultMessage());
            list.add(map);
        }
        BiException biException=new BiException("参数校验失败-"+exception);
        biException.setErrors(list);
        return this.handleExceptionInternal(biException, (Object)null, headers, status, request);
    }
    @Override
    protected ResponseEntity<Object> handleBindException(BindException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        List<FieldError> fieldErrors=ex.getBindingResult().getFieldErrors();
        List list=new LinkedList();
        String exception="";
        for (FieldError fieldError : fieldErrors) {
            if(StringUtils.isEmpty(exception)){
                exception=fieldError.getField()+"·"+fieldError.getDefaultMessage();
            }
            Map map=new LinkedHashMap();
            map.put("field",fieldError.getField());
            map.put("message",fieldError.getDefaultMessage());
            list.add(map);
        }
        BiException biException=new BiException("参数校验失败-"+exception);
        biException.setErrors(list);
        return this.handleExceptionInternal(biException, (Object)null, headers, status, request);
    }

    @Data
    public static class BiException extends RuntimeException {
        private Object errors;
        private String exception;
        public BiException(String message) {
            super(message);
        }
        public BiException(String message,Object errors) {
            super(message);
            this.errors=errors;
        }
    }
}